
#include <BFont>
#include <BPainter>
#include <BMouseEvent>
#include <BKeyEvent>
#include <BScrollBar>

#include "IAlignment.h"
#include "ITabBoard.h"
#include "member_BTabWidget.h"
#include "member_BWidget.h"
#include "member_BObject.h"

using namespace BWE;

void TabItem::translateText(const BStyle* style)
{
	if (!widget)
		return;
	if (widget_member(widget)->t_title.size())
		block.text = widget_member(widget)->t_title;
}

void TabItem::freshSize(const BFont* font, int width)
{
	if (widget_member(widget)->icon != icon)
		icon = widget_member(widget)->icon;
	IAlignItem::freshSize(font, width);
	if (closeButton)
	{
		int height = closeButton->height() + shellSize.height();
		if (hintSize.height() < height)
			hintSize.height() = height;
		hintSize.width() += closeButton->width() + spacing;
		hintSize.limit(minSize, maxSize);
	}
}

ITabBoard::ITabBoard(BTabWidget* tabWidget) : BScrollArea(tabWidget)
{
	this->setVisible(false);
	this->items = items;

	boss = tabWidget;
	itemSpacing = 3;
	dirty = true;
	hoveredIndex = -1;
	pressedIndex = -1;
	maxShowCount = 20;
}
ITabBoard::~ITabBoard()
{

}

void ITabBoard::freshItemRects()
{
	const BStyle* style = this->realStyle();
	const BFont* font = this->realFont();

	Align align = tab_member(boss)->tabAlign;
	int spacing = tab_member(boss)->tabSpacing;

	contentSize.reset();
	if (items.size())
	{
		for (int i = 0; i < items.size(); i++)
		{
			TabItem* item = items[i];
			if (item->closeButton)
			{
				BSize hsize = item->closeButton->sizeHint();
				if (item->closeButton->setSize(hsize))
					item->dirty = true;
			}
			if (item->dirtyStyle)
			{
				item->dispenseStyles(style);
				item->applyStyle(style);
				item->dirtyStyle = false;
				item->dirty = true;
			}
			if (item->dirty)
			{
				item->freshSize(font, 0);
				item->dirty = false;
			}
			contentSize.height() += item->hintSize.height() + itemSpacing;
			contentSize.width() = bMax(contentSize.width(), item->hintSize.width());
		}
		contentSize.height() -= itemSpacing;
	}
	this->setAreaSize(contentSize);
	int width = this->area().width();
	if (items.size())
	{
		int posY = 0;
		for (int i = 0; i < items.size(); i++)
		{
			TabItem* item = items[i];
			item->setPos(0, posY);
			item->setSize(width, item->hintSize.height());
			posY += item->size.height() + itemSpacing;
			if (item->closeButton)
			{
				item->closeArea = item->rectCenter;
				item->closeArea.left() = item->closeArea.right() - item->closeButton->width();
				item->closeArea += item->pos;
				BRect closeRect = item->closeArea.align(Align_Center, item->closeButton->size());
				item->closeButton->setRect(closeRect);
			}
		}
		scrolling(Orientation_Crossing);
	}
}

BSize ITabBoard::sizeHint() const
{
	if (dirty)
	{
		((ITabBoard*)this)->freshItemRects();
		dirty = false;
	}
	BSize hsize = this->preferSize(contentSize);
	return hsize;
}

void ITabBoard::scrolling(Orientation orientation)
{
	showBegin = -1;
	showEnd = -1;
	BRect crect = this->centerRect();
	BPoint offset = this->area().pos();
	for (int i = 0; i < items.size(); i++)
	{
		TabItem* item = items[i];
		BRect rect = item->rect() + offset;
		if (rect.bottom() > crect.top())
		{
			showBegin = i;
			showEnd = i;
			break;
		}
	}
	if (showBegin >= 0)
	{
		while (showEnd < items.size())
		{
			TabItem* item = items[showEnd];
			BRect rect = item->rect() + offset;
			if (rect.top() > crect.bottom())
				break;
			showEnd++;
		}
	}
	for (int i = 0; i < items.size(); i++)
	{
		TabItem* item = items[i];
		if (item->closeButton)
		{
			BRect closeArea = item->closeArea + offset;
			BRect closeRect = closeArea.align(Align_Center, item->closeButton->size());
			item->closeButton->setRect(closeRect);
		}
	}
	this->fresh();
	BScrollArea::scrolling(orientation);
}

void ITabBoard::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	dirty = true;
}

void ITabBoard::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	dirty = true;
}
void ITabBoard::freshEvent(const BEvent& event)
{
	if (dirty)
	{
		dirty = false;
		freshItemRects();
		BRect area = this->area();
		area.setSize(contentSize);
		this->setArea(area);
	}
	BScrollArea::freshEvent(event);
}
void ITabBoard::paintEvent(const BEvent& event)
{
	BScrollArea::paintEvent(event);

	const BRect& crect = this->centerRect();
	BPoint offset = this->offset();

	BPainter painter(this);
	State state = painter.state();

	painter.setClip(crect);
	for (int i = showBegin; i < showEnd; i++)
	{
		TabItem* item = items[i];
		BRect rect = item->rect() + offset;

		State itemState = state;
		if (pressedIndex == i)
			itemState |= State_Pressed;
		if (hoveredIndex == i)
			itemState |= State_Hovered;
		painter.pushMatrix();
		painter.translate(item->pos + offset);
		//painter.setClip(item_member(item)->rect() & crect);
		painter.setStyle(item->realStyle);
		item->drawBackground(painter, itemState);
		if (item->margin.valid())
			item->drawMargin(painter, itemState);
		if (item->border > 0)
			item->drawBorder(painter, itemState);
		item->drawContent(painter, itemState);
		painter.popMatrix();
	}
}

void ITabBoard::keyPressEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_Enter)
	{
		boss->setCurrentIndex(hoveredIndex);
		this->hide();
		keyEvent.accept();
	}

	int index = hoveredIndex;
	if (keyEvent.key() == Key_Up)
	{
		index--;
		if (index < 0)
			index = 0;
	}
	if (keyEvent.key() == Key_Down)
	{
		index++;
		if (index >= items.size())
			index = items.size() - 1;
	}
	if (hoveredIndex != index)
	{
		hoveredIndex = index;
		fresh();
	}

	BScrollArea::keyPressEvent(keyEvent);
}

void ITabBoard::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	if (hoveredIndex != -1)
	{
		hoveredIndex = -1;
		this->fresh();
	}
	BScrollArea::mouseEnterEvent(mouseEvent);
}
void ITabBoard::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (hoveredIndex != -1)
	{
		hoveredIndex = -1;
		this->fresh();
	}
	BScrollArea::mouseLeaveEvent(mouseEvent);
}

void ITabBoard::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (hoveredIndex >= 0)
	{
		TabItem* item = items[hoveredIndex];
		item->dirtyStyle = true;
		item->dirty = true;
		tab_member(boss)->items.raise(item->widget);
		tab_member(boss)->dirty = true;
		boss->setCurrent(item->widget);
		object_member(boss)->emit(Signal_TabClicked, item->widget);
	}
	arrow->setChecked(!arrow->checked());
	BScrollArea::mouseClickEvent(mouseEvent);
}
void ITabBoard::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	const BRect& crect = this->centerRect();
	int index = -1;
	if (crect.contain(pos))
	{
		BPoint offset = this->area().pos();
		for (int i = showBegin; i < showEnd; i++)
		{
			TabItem* item = items[i];
			BRect rect = item->rect() + offset;
			if (rect.contain(pos))
			{
				index = i;
				break;
			}
		}
	}
	if (hoveredIndex != index)
	{
		hoveredIndex = index;
		object_member(boss)->emit(Signal_ItemHovered, hoveredIndex);
		fresh();
	}
	BScrollArea::mouseMoveEvent(mouseEvent);
}
